#ifndef __GAMELAYER_H__
#define __GAMELAYER_H__
#include "cocos2d.h"
#include "Box2D/Box2D.h"
#include "GLES-Render.h"
#include "GB2ShapeCache.h"
#include "Com/Launcher.h"
#include "Dialog.h"
#include "GameScene.h"
#include "util.h"
#include "Data/CommonData.h"
#include "Persistence.h"
#include "SimpleAudioEngine.h"
#include "Com/Gesture.h"
#include <list>

USING_NS_CC;

#define PTM_RATIO 32.0f
#define WIDTH 800.0f
#define HEIGHT 480.0f

//#define DRAW_DEBUG
namespace suta
{
	class GameScene;

	class EffectToggle:public CCLayer
	{
		bool m_bEnabled;
	public:

		bool init()
		{
			bool ret=false;
			do 
			{
				CC_BREAK_IF(!CCLayer::init());
				m_bEnabled=Persistence::shardPersiatence()->getEffectEnabled();
				
				CocosDenshion::SimpleAudioEngine::sharedEngine()->setEffectsVolume(m_bEnabled?1.0f:0.0f);
				CocosDenshion::SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(m_bEnabled?1.0f:0.0f);

				setContentSize(CCSizeMake(30,30));
				setIsRelativeAnchorPoint(true);
				
				CCMenuItemImage*enabledMenuItem=CCMenuItemImage::itemFromNormalImage("effect_enabled.png",NULL);
				CCMenuItemImage*disabledMenuItem=CCMenuItemImage::itemFromNormalImage("effect_disabled.png",NULL);

				CCMenuItemToggle *toggle=CCMenuItemToggle::itemWithTarget(this,menu_selector(EffectToggle::callBackClicked),enabledMenuItem,disabledMenuItem,NULL);
				toggle->setSelectedIndex(m_bEnabled?0:1);
				
				CCMenu*menu=CCMenu::menuWithItem(toggle);
				menu->setPosition(ccp(15,15));
				addChild(menu);
				ret=true;
			} while (0);
			return ret;
		};
		LAYER_NODE_FUNC(EffectToggle);
		void callBackClicked(CCObject*pSender){
			m_bEnabled=!m_bEnabled;
			CocosDenshion::SimpleAudioEngine::sharedEngine()->setEffectsVolume(m_bEnabled?1.0f:0.0f);
			CocosDenshion::SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(m_bEnabled?1.0f:0.0f);

			Persistence::shardPersiatence()->setEffectEnabled(m_bEnabled);
		};
	};


	class GameLayer:public CCLayer,public b2ContactListener,public LauncherListener,public  DialogListener
	{
		typedef void (GameLayer::*_init_world)();
	private:

#ifdef DRAW_DEBUG
		GLESDebugDraw *m_b2dDebugDraw ;
		void draw();
#endif // DRAW_DEBUG

		_init_world m_aInitWorld[16];//15 levels and 1 menu

		int m_iLevel;
		int m_iBallCnt;
		int m_iTargetCnt;
		int m_iLauncherCreatedCnt;
		list<b2Body*>m_dynamic;
		CCLabelBMFont *m_pLabelBallCnt;
		CCSprite*m_pLastAim;
		CCSprite*m_pAim;
		PauseDialog*m_pPauseDialog;
		void initBox2D();
		b2Body* loadGB2();

		inline void slideDownDialog(Dialog*dialog)
		{
			dialog->setPosition(ccp(0,480));
			CCMoveTo*move=CCMoveTo::actionWithDuration(0.6f,ccp(0,0));
			dialog->runAction(move);
		};

		inline void slideUpDialog(Dialog*dialog)
		{
			CCMoveTo*move=CCMoveTo::actionWithDuration(0.6f,ccp(0,480));
			dialog->runAction(move);
		};

	protected:
		b2World *m_pWorld;
		bool m_bOver;
		bool m_bPaused;
		int m_iStarsCnt;
		CCSprite*m_stars[3];
		Launcher*m_pLauncher;

		void incrStar();
		inline void setBallCnt(int cnt){
			char str[5]={0};
			m_iBallCnt=cnt;
			SPRINTF(str,5,"X%d",m_iBallCnt);
			m_pLabelBallCnt->setString(str);
		};
		inline void incrBallCnt(int num){setBallCnt(num+m_iBallCnt);};
		inline void decrBallCnt(){setBallCnt(m_iBallCnt-1);};

		bool isWorldSleep();

		void createLauncher(float x,float y);
		void createTarget(float x,float y);
		void createStar(float x,float y);
		void createIncr(float x,float y,int num);
		b2Body* createRotate(float x,float y,float width,float height,float angle,bool autoRotate=false,bool rotateRight=true);
		void createRotateTriangle(float x,float y,float startAngle,bool rotateRight=true);
		b2Body* createBox(float x,float y,float size,bool active=true);
		b2Body* createWood(float x,float y,float width,float height,float angle=0);
	public:
		GameLayer():
		  CCLayer(),
		  m_pWorld(NULL),
		  m_pLauncher(NULL),
		  m_pLabelBallCnt(NULL),
		  m_pLastAim(NULL),
		  m_pAim(NULL),
		  m_pPauseDialog(NULL),
		  m_bOver(false),
		  m_bPaused(false),
		  m_iBallCnt(0),
		  m_iTargetCnt(0),
		  m_iLauncherCreatedCnt(0),
		  m_iStarsCnt(0){};
		bool init(int level);
		LAYER_NODE_FUNC_PARAM(GameLayer,int,level);

		void step(ccTime dt);
		void launchBall(float dx,float dy);
		void callbackPause(CCObject*pSender);
		void over(bool succeed);
		void resume();

		void BeginContact(b2Contact* contact);

		void onStartAiming();
		void onEndAiming(float dx,float dy);
		void onMoveAiming(float dx,float dy);

		void onResume(){resume();};
		void onRestart();
		void onNext();
	private:
		void initWorldLevel0()
		{
			loadGB2();

			createLauncher(800-40,25*3);
			createStar(300,339);
			createStar(432,51);
			createStar(78,212);
			createTarget(216,51);

			CCPoint p=m_pLauncher->getPosition();
			{
				Gesture*gexture=Gesture::node(p);
				addChild(gexture);
				
			}
		};
		void initWorldLevel1()
		{
			loadGB2();

			createLauncher(800-40,25*3);
			createStar(78,255);
			createStar(420,200);
			createStar(299,30);
			createTarget(420,30);

			createRotate(106,135,100,20,0,true);
		};
		void initWorldLevel2()
		{
			loadGB2();

			createLauncher(800-40,25*3);
			createStar(168,303);
			createStar(120,93);
			createStar(84,393);
			createTarget(432,51);

			createRotate(168,430,100,20,0,true);
			createRotate(168,177,100,20,0,true,false);
		};
		void initWorldLevel3()
		{
			loadGB2();

			createLauncher(800-40,25*3);
			createStar(126,105);
			createStar(360,51);
			createStar(402,249);
			createTarget(93,33);
		};
		void initWorldLevel4()
		{
			loadGB2();

			createLauncher(800-40,25*3);
			createStar(126,80);
			createStar(340,51);
			createStar(402,320);
			createTarget(450,45);

			createIncr(40,320,3);

			createRotate(216,291,60,12,0);
			createRotate(155,155,110,20,0,true,false);
			createRotate(277,155,110,20,0,true);
		};
		void initWorldLevel5()
		{

			createLauncher(800-40*3,25*5);
			createStar(210,180);
			createStar(340,51);
			createStar(360,310);
			createTarget(250,250);
			createBox(250,215,40,false);

			createIncr(200,300,2);

			createRotateTriangle(100,380,0);
			createRotateTriangle(250,380,3.14f/6);
			createRotateTriangle(400,380,3.14f/4,false);
			createRotateTriangle(100,240,3.14f/2);
			createRotateTriangle(400,240,3.14f/2,false);
			createRotateTriangle(100,100,3.14f/4);
			createRotateTriangle(250,100,3.14f/5,false);
			createRotateTriangle(400,100,0);
		};
		void initWorldLevel6()
		{
			createLauncher(800-40*3,25*5);
			createStar(50,180);
			createStar(400,200);
			createStar(230,400);
			createTarget(20,20);

			createIncr(350,370,4);

			createBox(130,25,50);
			createBox(130,75,50);
			createWood(130,110,250,20);
			createBox(130,145,50);

			for (int i=0;i<5;i++)
			{
				createBox(350,35.0f+i*70,70);
			}
		};
		void initWorldLevel7()
		{
			createLauncher(800-40*3,25*5);
			createStar(17,180);
			createStar(330,51);
			createStar(230,350);
			createTarget(20,15);

			for (int i=0;i<15;i++)
			{
				createBox(25.0f+i*50,405,50,false);
			}
			createRotate(375,290,160,20,3.14f/2);
			createRotate(130,290,120,20,0,true);
			for (int c=0;c<4;c++)
			{
				for (int r=0;r<4;r++)
				{
					createBox(375.0f-c*100,25.0f+r*50,50);
				}
			}

		};
		void initWorldLevel8()
		{

			float boxSize=50.0f;
			float woodHeight=25.0f;
			float bigWoodWidth=400.0f,smallWoodWidth=150.0f;

			createLauncher(800-40*3,25*5);
			createStar(300,180);
			createStar(350,51);
			createStar(260,375);
			createTarget(300,boxSize*2+woodHeight+15);

			createIncr(350,370,7);


			createBox(300,boxSize*0.5f,boxSize);
			createBox(300,boxSize*1.5f,boxSize);
			createWood(300,boxSize*2+woodHeight*0.5f,bigWoodWidth,woodHeight);
			createBox(300-bigWoodWidth*0.5f+boxSize*0.5f,boxSize*2.5f+woodHeight,boxSize);
			createBox(300+bigWoodWidth*0.5f-boxSize*0.5f,boxSize*2.5f+woodHeight,boxSize);
			createBox(300-bigWoodWidth*0.5f+boxSize*0.5f,boxSize*3.5f+woodHeight,boxSize);
			createBox(300+bigWoodWidth*0.5f-boxSize*0.5f,boxSize*3.5f+woodHeight,boxSize);
			createWood(300-bigWoodWidth*0.5f+boxSize*0.5f,boxSize*4+woodHeight*1.5f,smallWoodWidth,woodHeight);
			createWood(300+bigWoodWidth*0.5f-boxSize*0.5f,boxSize*4+woodHeight*1.5f,smallWoodWidth,woodHeight);
			createBox(300-bigWoodWidth*0.5f-smallWoodWidth*0.5f+boxSize,boxSize*4.5f+woodHeight*2,boxSize,false);
			createBox(300-bigWoodWidth*0.5f+smallWoodWidth*0.5f,boxSize*4.5f+woodHeight*2,boxSize,true);
			createBox(300+bigWoodWidth*0.5f+smallWoodWidth*0.5f-boxSize,boxSize*4.5f+woodHeight*2,boxSize,false);
			createBox(300+bigWoodWidth*0.5f-smallWoodWidth*0.5f,boxSize*4.5f+woodHeight*2,boxSize,true);
			createWood(300,boxSize*5+woodHeight*2.5f,bigWoodWidth-boxSize,woodHeight);
			createBox(300,5.5f*boxSize+3*woodHeight,boxSize);

		};
		void initWorldLevel9()
		{
			loadGB2();
			createLauncher(800-40*3,25*5);
			createStar(20,180);
			createStar(350,51);
			createStar(260,375);
			createTarget(88,353);

			createBox(118,353,30);

			for (int i=0;i<4;i++)
			{
				createBox(48.0f+30*i,385,30,false);
			}
			createBox(48,415,30,false);
			createBox(15,290,30,false);

			createRotate(72,159,130,20,0,true,false);
		};
		void initWorldLevel10()
		{
			createLauncher(800-40*3,25*5);
			createStar(300,180);
			createStar(50,80);
			createStar(260,375);
			createTarget(15,15);
			createTarget(15,430);
			createTarget(200,15);

			for (int i=0;i<6;i++)
			{
				createBox(15.0f+30*i,400,30,false);
			}

			b2Body*axis,*wood;
			{
				b2BodyDef def;
				def.type=b2_staticBody;

				axis=m_pWorld->CreateBody(&def);

				b2CircleShape shape;
				shape.m_radius=10/PTM_RATIO;
				b2FixtureDef fdef;
				fdef.shape=&shape;
				
				axis->CreateFixture(&fdef);
				axis->SetTransform(b2Vec2(150/PTM_RATIO,240/PTM_RATIO),0);

				CCSprite*axis=CCSprite::spriteWithFile("axis.png");
				axis->setPosition(ccp(150,240));
				addChild(axis,1);
			}
			{
				b2BodyDef def;
				def.type=b2_dynamicBody;
				def.angularDamping=0.3f;

				wood=m_pWorld->CreateBody(&def);

				b2PolygonShape shape;
				shape.SetAsBox(70/PTM_RATIO,10/PTM_RATIO);
				b2FixtureDef fdef;
				fdef.shape=&shape;
				fdef.density=3.0f;
				fdef.friction=0.3f;
				fdef.restitution=0.4f;

				wood->CreateFixture(&fdef);
				wood->SetTransform(b2Vec2(150/PTM_RATIO,300/PTM_RATIO),3.14f/2);

				WallData*data=WallData::node(140,20);
				addChild(data);
				wood->SetUserData(data);
			}

			b2RevoluteJointDef jointDef;
			jointDef.Initialize(wood,axis,axis->GetPosition());
			m_pWorld->CreateJoint(&jointDef);

			createWood(150,110,220,20,3.14f/2);
			createWood(250,110,220,20,3.14f/2);
			createWood(350,110,220,20,3.14f/2);
			createWood(450,110,220,20,3.14f/2);

		};

		void initWorldLevel11()
		{
			createLauncher(800-40*3,25*5);
			createStar(450,180);
			createStar(15,80);
			createStar(260,100);
			createTarget(50,190+15);

			createIncr(260,30,3);
			
			float y=420;
			for (int i=2;i<=5;i++)
			{
				float x=i*100.0f;
				b2Body*pre=createBox(x,y,30,false);
				for (int j=1;j<7;j++)
				{
					b2Body*thiz=createWood(x,y-j*40,50,10,3.14f/2);
					b2RevoluteJointDef jointDef;
					jointDef.Initialize(thiz,pre,b2Vec2(x/PTM_RATIO,(y-j*40+20)/PTM_RATIO));
					m_pWorld->CreateJoint(&jointDef);

					pre=thiz;

					m_dynamic.remove(thiz);
				}
				b2Body*box=createBox(x,pre->GetPosition().y*PTM_RATIO-20,50);
				b2RevoluteJointDef jointDef;
				jointDef.Initialize(box,pre,box->GetPosition());
				m_pWorld->CreateJoint(&jointDef);
				
				m_dynamic.remove(box);
			}

			createWood(100,180,140,20);
			createBox(110,150,40,false);
		};
		
		void initWorldLevel12()
		{

			createLauncher(800-40*3,25*5);
			createStar(450,180);
			createStar(15,350);
			createStar(260,100);
			createTarget(105,259+15);
			createTarget(300,170);

			createIncr(250,350,5);

			b2Body*gb=loadGB2();

			{
				b2Body*wood=createWood(80,320,108,16,3.14f/2);
				b2RevoluteJointDef jointDef;
				jointDef.Initialize(wood,gb,wood->GetPosition());
				m_pWorld->CreateJoint(&jointDef);

				{
					CCSprite*sprite=CCSprite::spriteWithFile("axis.png");
					sprite->setPosition(ccp(wood->GetPosition().x*PTM_RATIO,wood->GetPosition().y*PTM_RATIO));
					addChild(sprite);
				}
			}
			{
				b2Body*wood=createWood(375,320,120,16,3.14f/2);
				b2RevoluteJointDef jointDef;
				jointDef.Initialize(wood,gb,wood->GetPosition());
				m_pWorld->CreateJoint(&jointDef);

				{
					CCSprite*sprite=CCSprite::spriteWithFile("axis.png");
					sprite->setPosition(ccp(wood->GetPosition().x*PTM_RATIO,wood->GetPosition().y*PTM_RATIO));
					addChild(sprite);
				}
				
				b2Body* activeWood=createWood(375,220,110,14,3.14f/2);
				b2Body *activeAxis;
				{
					b2BodyDef def;
					def.type=b2_dynamicBody;
					activeAxis=m_pWorld->CreateBody(&def);
					b2CircleShape shape;
					shape.m_radius=10/PTM_RATIO;

					b2FixtureDef fdef;
					fdef.shape=&shape;
					fdef.density=5.0f;
					fdef.friction=0.5f;

					activeAxis->CreateFixture(&fdef);
					activeAxis->SetTransform(b2Vec2(375.0/PTM_RATIO,270.0/PTM_RATIO),0);

					WallData*data=WallData::node(CCSprite::spriteWithFile("axis.png"));
					addChild(data);

					activeAxis->SetUserData(data);
				}

				jointDef.Initialize(activeAxis,wood,activeAxis->GetPosition());
				m_pWorld->CreateJoint(&jointDef);

				jointDef.Initialize(activeWood,wood,activeAxis->GetPosition());
				m_pWorld->CreateJoint(&jointDef);
				
			}

		};

		void initWorldLevel13()
		{
			createLauncher(800-40*3,25*5);
			createStar(450,180);
			createStar(15,80);
			createStar(260,20);
			createTarget(15,15);
			createTarget(120,15);

			createIncr(320,40,5);

			for (int i=0;i<4;i++)
			{
				b2Body*center,*circle;
				{
					b2BodyDef def;
					def.type=b2_staticBody;
					center=m_pWorld->CreateBody(&def);
					b2CircleShape shape;
					shape.m_radius=1/PTM_RATIO;

					b2FixtureDef fdef;
					fdef.shape=&shape;
					fdef.restitution=0.5f;

					center->CreateFixture(&fdef);
					center->SetTransform(b2Vec2((100+i*120)/PTM_RATIO,100/PTM_RATIO),0);
				}
				{
					b2BodyDef def;
					def.type=b2_dynamicBody;
					circle=m_pWorld->CreateBody(&def);
					b2CircleShape shape;
					shape.m_radius=40/PTM_RATIO;

					b2FixtureDef fdef;
					fdef.shape=&shape;
					fdef.density=3.0f;
					fdef.friction=0.2f;
					fdef.restitution=0.5f;

					circle->CreateFixture(&fdef);
					circle->SetTransform(center->GetPosition(),0);

					WallData*data=WallData::node(CCSprite::spriteWithFile("gear.png"));
					addChild(data);
					circle->SetUserData(data);
				}

				b2RevoluteJointDef jointDef;
				jointDef.Initialize(circle,center,center->GetPosition());
				jointDef.enableMotor=true;
				jointDef.motorSpeed=-3.14f/2;
				jointDef.maxMotorTorque=10000.0f;

				m_pWorld->CreateJoint(&jointDef);
			}

			createBox(460,25,50,false);
			createBox(100,25,50,false);

			createBox(580,100,50,false);
			b2Body*wood=createWood(580,225,200,20,3.14f/2);
			m_dynamic.remove(wood);

			{
				b2Body*rotate=createRotate(200,300,180,16,0,true);
				b2Body*left=createWood(120,300,130,12,3.14f/2);
				b2Body*right=createWood(280,300,130,12,3.14f/2);

				m_dynamic.remove(left);
				m_dynamic.remove(right);

				b2RevoluteJointDef jointDef;
				jointDef.Initialize(left,rotate,left->GetPosition());
				jointDef.enableMotor=true;
				jointDef.motorSpeed=3.14f;
				jointDef.maxMotorTorque=10000.0f;
				m_pWorld->CreateJoint(&jointDef);

				jointDef.Initialize(right,rotate,right->GetPosition());
				jointDef.enableMotor=true;
				jointDef.motorSpeed=-3.14f;
				jointDef.maxMotorTorque=10000.0f;
				m_pWorld->CreateJoint(&jointDef);
			}


		};

		void initWorldLevel14()
		{
			loadGB2();

			createLauncher(800-40*3,25*5);
			createStar(450,180);
			createStar(15,80);
			createStar(260,100);
			createTarget(241,23);

			float xA[13]={100,100,100,200,200,300,300,300,400,400,500,500,500};
			float yA[13]={360,240,120,300,180,360,240,120,300,180,360,240,120};
			bool rA=true;//[13]={false,false,false,false,false,true,false,true,true,true,true,true,true};

			for (int i=0;i<13;i++)
			{
				createRotate(xA[i],yA[i],100,16,3.14f/2,true,rA=!rA);
			}
		};

		void initWorldMenu()
		{
			createLauncher(800-40*3,25*5);
			createStar(450,240);
			createStar(15,80);
			createStar(260,100);
			createTarget(15,15);

			createIncr(200,300,8);
			createIncr(400,400,7);
			createIncr(600,200,6);

			for (int c=0;c<6;c++)
			{
				for (int r=0;r<4;r++)
				{
					createBox(100.0f*(1+c),25.0f+r*50,50);
				}
			}

			{
				CCMenuItemImage*play=CCMenuItemImage::itemFromNormalImage("menu/start.png",NULL,this,menu_selector(GameLayer::onPlayClicked));
				
				CCScaleTo*scaleOut=CCScaleTo::actionWithDuration(0.8f,0.85f);
				CCScaleTo*scaleIn=CCScaleTo::actionWithDuration(0.8f,1.0f);
				CCSequence*seq=CCSequence::actionOneTwo(scaleOut,scaleIn);
				CCRepeatForever*repeat=CCRepeatForever::actionWithAction(seq);
				play->runAction(repeat);
				
				b2BodyDef def;
				def.type=b2_dynamicBody;
				b2Body*menuBody=m_pWorld->CreateBody(&def);
				b2PolygonShape shape;
				shape.SetAsBox(208/(2*PTM_RATIO),83/(2*PTM_RATIO));

				b2FixtureDef fdef;
				fdef.shape=&shape;
				fdef.density=50.0f;
				fdef.restitution=0.5f;
				fdef.friction=0.5f;

				menuBody->CreateFixture(&fdef);
				menuBody->SetTransform(b2Vec2(200/PTM_RATIO,620/PTM_RATIO),0);

				MenuData*data=MenuData::node(play);
				addChild(data);
				menuBody->SetUserData(data);

			}
			{
				CCMenuItemImage*exit=CCMenuItemImage::itemFromNormalImage("menu/stop.png",NULL,this,menu_selector(GameLayer::onExitClicked));
				b2BodyDef def;
				def.type=b2_dynamicBody;
				b2Body*menuBody=m_pWorld->CreateBody(&def);
				b2PolygonShape shape;
				shape.SetAsBox(208/(2*PTM_RATIO),83/(2*PTM_RATIO));

				b2FixtureDef fdef;
				fdef.shape=&shape;
				fdef.density=40.0f;
				fdef.restitution=0.5f;
				fdef.friction=0.5f;

				menuBody->CreateFixture(&fdef);
				menuBody->SetTransform(b2Vec2(500/PTM_RATIO,530/PTM_RATIO),0);

				MenuData*data=MenuData::node(exit);
				addChild(data);
				menuBody->SetUserData(data);

			}
			{
				CCMenuItemImage*help=CCMenuItemImage::itemFromNormalImage("menu/help.png",NULL,this,menu_selector(GameLayer::onHelpClicked));
				b2BodyDef def;
				def.type=b2_dynamicBody;
				b2Body*menuBody=m_pWorld->CreateBody(&def);
				b2PolygonShape shape;
				shape.SetAsBox(208/(2*PTM_RATIO),83/(2*PTM_RATIO));

				b2FixtureDef fdef;
				fdef.shape=&shape;
				fdef.density=15.0f;
				fdef.restitution=0.5f;
				fdef.friction=0.5f;

				menuBody->CreateFixture(&fdef);
				menuBody->SetTransform(b2Vec2(400/PTM_RATIO,800/PTM_RATIO),0);

				MenuData*data=MenuData::node(help);
				addChild(data);
				menuBody->SetUserData(data);

			}
			
		};

		void onPlayClicked(CCObject*pSender);
		void onExitClicked(CCObject*pSender);
		void onHelpClicked(CCObject*pSender);

	};
}
#endif//__GAMELAYER_H__